实现模板时，有时会出现这样的问题:代码是否能够处理不完整的类型(参见10.3.1节)。来看看下面的类模板:

\begin{lstlisting}[style=styleCXX]
template<typename T>
class Cont {
private:
	T* elems;
public:
	...
};
\end{lstlisting}

这个类可以与不完整类型一起使用。例如：当类引用自己类型的元素时:

\begin{lstlisting}[style=styleCXX]
struct Node
{
	std::string value;
	Cont<Node> next; // only possible if Cont accepts incomplete types
};
\end{lstlisting}

然而，仅通过使用一些特性，就会失去处理不完整类型的能力。例如:

\begin{lstlisting}[style=styleCXX]
template<typename T>
class Cont {
private:
	T* elems;
public:
	...
	typename std::conditional<std::is_move_constructible<T>::value,
					T&&,
					T&
					>::type
	foo();
};
\end{lstlisting}

这里，使用特征std::conditional(参见D.5节)来决定成员函数foo()的返回类型是T\&\&还是T\&。这取决于模板参数类型T是否支持移动语义。

问题是特性std::is\_move\_constructible要求参数是一个完整的类型(不是void或未知边界的数组;参见的D.3.2节)。在foo()的这个声明中，struct Node的声明失败了。

\begin{tcolorbox}[colback=webgreen!5!white,colframe=webgreen!75!black]
\hspace*{0.75cm}如果std::is\_move\_constructible是一个完整的类型，并不是所有的编译器都会产生错误。因为对于这种错误，不需要进行诊断。所以，在需要平台移植时需要考虑这个问题。
\end{tcolorbox}

可以将foo()替换为成员模板来解决这个问题，这样std::is\_move\_constructible的计算就会延迟到foo()的实例化点:

\begin{lstlisting}[style=styleCXX]
template<typename T>
class Cont {
private:
	T* elems;
public:
	template<typename D = T> std::conditional<std::is_move_constructible<T>::value,
					T&&,
					T&
					>::type
	foo();
};
\end{lstlisting}

现在，特性依赖于模板参数D(默认为T，我们想要的值)，编译器必须等到foo()调，如Node之前，再评估特性(那时Node是一个完整的类型，只是在定义时不完整)。











